namespace HZY.Framework.Repository.EntityFramework.Attributes;

/// <summary>
/// 表字段属性, 用于记录字段 是 创建时间、创建人、更新时间、更新人 、删除时间、删除人
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public class TableFieldAttribute : Attribute
{
    public TableFieldAttribute(TableFieldFill tableFieldFill)
    {
        _tableFieldFill = tableFieldFill;
        IsUtcTime = false;
    }

    public TableFieldAttribute(TableFieldFill tableFieldFill, bool isUtcTime = false)
    {
        _tableFieldFill = tableFieldFill;
        IsUtcTime = isUtcTime;
    }

    /// <summary>
    /// 
    /// </summary>
    private readonly TableFieldFill _tableFieldFill;

    /// <summary>
    /// 是否采用 utc 时间
    /// </summary>
    private bool IsUtcTime { get; } = false;

    /// <summary>
    /// 是否填充字段
    /// </summary>
    public bool IsFill { get; set; } = true;

    /// <summary>
    /// 根据字段填充类型获取字段
    /// </summary>
    /// <param name="propertyInfo"></param>
    /// <returns></returns>
    public static TableFieldAttribute? GetTableFieldAttribute(PropertyInfo propertyInfo)
    {
        return propertyInfo.GetCustomAttribute<TableFieldAttribute>();
    }

    /// <summary>
    /// 处理填充字段
    /// </summary>
    /// <param name="entityEntry"></param>
    /// <param name="propertyEntry"></param>
    /// <param name="entityState"></param>
    /// <param name="currentUserId"></param>
    /// <exception cref="ArgumentOutOfRangeException"></exception>
    public virtual void HandleFill(EntityEntry entityEntry, PropertyEntry propertyEntry, EntityState entityState,
        object? currentUserId)
    {
        // var entityType = entityEntry.Metadata.ClrType;
        if (!IsFill)
        {
            return;
        }

        switch (_tableFieldFill)
        {
            case TableFieldFill.CreateTime:
                if (entityState == EntityState.Added)
                {
                    this.HandleTime(propertyEntry, entityState);
                }

                break;
            case TableFieldFill.CreateId:
                if (entityState == EntityState.Added)
                {
                    this.HandleId(propertyEntry, currentUserId);
                }

                break;
            case TableFieldFill.UpdateTime:
                if (entityState == EntityState.Modified)
                {
                    this.HandleTime(propertyEntry, entityState);
                }

                break;
            case TableFieldFill.UpdateId:
                if (entityState == EntityState.Modified)
                {
                    this.HandleId(propertyEntry, currentUserId);
                }

                break;
            case TableFieldFill.DeleteTime:
                if (entityState == EntityState.Deleted)
                {
                    this.HandleTime(propertyEntry, entityState);
                }

                break;
            case TableFieldFill.DeleteId:
                if (entityState == EntityState.Deleted)
                {
                    this.HandleId(propertyEntry, currentUserId);
                }

                break;
            default:
                throw new ArgumentOutOfRangeException();
        }
    }

    /// <summary>
    /// 处理 id
    /// </summary>
    /// <param name="propertyEntry"></param>
    /// <param name="currentUserId"></param>
    private void HandleId(PropertyEntry propertyEntry, object? currentUserId)
    {
        var propertyType = propertyEntry.Metadata.PropertyInfo?.PropertyType;
        var currVal = propertyEntry.CurrentValue;
        // userIdPropertyEntry
        if (propertyType == typeof(Guid) || propertyType == typeof(Guid?))
        {
            Guid.TryParse(currentUserId?.ToString(), out var guid);
            propertyEntry.CurrentValue = (guid == Guid.Empty ? currVal : guid);
        }
        else if (propertyType == typeof(long) || propertyType == typeof(long?))
        {
            long.TryParse(currentUserId?.ToString(), out var value);
            propertyEntry.CurrentValue ??= (value < 1 ? currVal : value);
        }
        else if (propertyType == typeof(int) || propertyType == typeof(int?))
        {
            int.TryParse(currentUserId?.ToString(), out var value);
            propertyEntry.CurrentValue ??= (value < 1 ? currVal : value);
        }
        else if (propertyType == typeof(string))
        {
            var value = currentUserId?.ToString();
            propertyEntry.CurrentValue ??= (string.IsNullOrWhiteSpace(value) ? currVal : value);
        }
        else
        {
            propertyEntry.CurrentValue = currentUserId;
        }
    }

    /// <summary>
    /// 处理时间
    /// </summary>
    /// <param name="propertyEntry"></param>
    /// <param name="entityState"></param>
    private void HandleTime(PropertyEntry propertyEntry, EntityState entityState)
    {
        var now = IsUtcTime ? DateTime.UtcNow : DateTime.Now;

        // 查找对象是否包含某个字段
        if (entityState == EntityState.Added)
        {
            // 创建时间处理
            propertyEntry.CurrentValue ??= now;

            if (propertyEntry.CurrentValue is DateTime time)
            {
                propertyEntry.CurrentValue = time > DateTime.MinValue
                    ? time
                    : now;
            }
        }

        if (entityState == EntityState.Modified)
        {
            // 如果有修改，那么就用修改的值 ，否则使用 当前时间
            if (propertyEntry is { CurrentValue: DateTime time, OriginalValue: DateTime timeOld })
            {
                if (time.Equals(timeOld))
                {
                    propertyEntry.CurrentValue = now;
                }
            }
            else
            {
                propertyEntry.CurrentValue = now;
            }
        }

        if (entityState == EntityState.Deleted)
        {
            if (propertyEntry.CurrentValue is DateTime time)
            {
                propertyEntry.CurrentValue = now;
            }
        }
    }

    #region FreeSqlAuditAop

    /// <summary>
    /// 处理填充字段
    /// </summary>
    /// <param name="auditInfo"></param>
    /// <param name="currentUserId"></param>
    /// <exception cref="ArgumentOutOfRangeException"></exception>
    public virtual void HandleFillByFreeSql(AuditValueEventArgs auditInfo, object? currentUserId)
    {
        // var entityType = entityEntry.Metadata.ClrType;

        // 如果是软删除，那么还需要取出删除软删除的字段的值来判定是否软删除
        // var propertyEntry = auditInfo.Object.GetType().GetProperties()
        //     .FirstOrDefault(x => x.Name == "IsDeleted");
        // if (propertyEntry != null)
        // {
        //     var propertyType = propertyEntry.Metadata.PropertyInfo?.PropertyType;
        //     // userIdPropertyEntry
        //     if (propertyType == typeof(Guid) || propertyType == typeof(Guid?))
        //     {
        //     }
        // }

        if (!IsFill)
        {
            return;
        }

        switch (_tableFieldFill)
        {
            case TableFieldFill.CreateTime:
                if (auditInfo.AuditValueType == AuditValueType.Insert)
                {
                    this.HandleTimeByFreeSql(auditInfo);
                }

                break;
            case TableFieldFill.CreateId:
                if (auditInfo.AuditValueType == AuditValueType.Insert)
                {
                    this.HandleIdByFreeSql(auditInfo, currentUserId);
                }

                break;
            case TableFieldFill.UpdateTime:
                if (auditInfo.AuditValueType == AuditValueType.Update ||
                    auditInfo.AuditValueType == AuditValueType.InsertOrUpdate)
                {
                    this.HandleTimeByFreeSql(auditInfo);
                }

                break;
            case TableFieldFill.UpdateId:
                if (auditInfo.AuditValueType == AuditValueType.Update ||
                    auditInfo.AuditValueType == AuditValueType.InsertOrUpdate)
                {
                    this.HandleIdByFreeSql(auditInfo, currentUserId);
                }

                break;
            case TableFieldFill.DeleteTime:
                if (auditInfo.AuditValueType == AuditValueType.Update ||
                    auditInfo.AuditValueType == AuditValueType.InsertOrUpdate)
                {
                    this.HandleTimeByFreeSql(auditInfo);
                }

                break;
            case TableFieldFill.DeleteId:
                if (auditInfo.AuditValueType == AuditValueType.Update ||
                    auditInfo.AuditValueType == AuditValueType.InsertOrUpdate)
                {
                    this.HandleIdByFreeSql(auditInfo, currentUserId);
                }

                break;
            default:
                throw new ArgumentOutOfRangeException();
        }
    }

    /// <summary>
    /// 处理时间字段
    /// </summary>
    /// <param name="auditInfo"></param>
    private void HandleTimeByFreeSql(AuditValueEventArgs auditInfo)
    {
        var now = IsUtcTime ? DateTime.UtcNow : DateTime.Now;

        // 查找对象是否包含某个字段
        if (auditInfo.AuditValueType == AuditValueType.Insert)
        {
            // 创建时间
            auditInfo.Value = (DateTime?)auditInfo.Value > DateTime.MinValue
                ? auditInfo.Value
                : now;
        }
        else if (auditInfo.AuditValueType == AuditValueType.Update)
        {
            // 如果没有发生变化，那么就使用当前时间
            if (!auditInfo.ValueIsChanged)
            {
                auditInfo.Value = now;
            }
        }
        else
        {
            auditInfo.Value = now;
        }
    }

    /// <summary>
    /// 处理操作人字段
    /// </summary>
    /// <param name="auditInfo"></param>
    /// <param name="currentUserId"></param>
    private void HandleIdByFreeSql(AuditValueEventArgs auditInfo, object? currentUserId)
    {
        // 创建人
        // 查找对象是否包含某个字段
        // userIdPropertyEntry
        var currVal = auditInfo.Value;
        if (auditInfo.Property.PropertyType == typeof(Guid) || auditInfo.Property.PropertyType == typeof(Guid?))
        {
            Guid.TryParse(currentUserId?.ToString(), out var guid);
            auditInfo.Value ??= (guid == Guid.Empty ? currVal : guid);
        }
        else if (auditInfo.Property.PropertyType == typeof(long) || auditInfo.Property.PropertyType == typeof(long?))
        {
            long.TryParse(currentUserId?.ToString(), out var value);
            auditInfo.Value ??= (value < 1 ? currVal : value);
        }
        else if (auditInfo.Property.PropertyType == typeof(int) || auditInfo.Property.PropertyType == typeof(int?))
        {
            int.TryParse(currentUserId?.ToString(), out var value);
            auditInfo.Value ??= (value < 1 ? currVal : value);
        }
        else if (auditInfo.Property.PropertyType == typeof(string))
        {
            var value = currentUserId?.ToString();
            auditInfo.Value ??= (string.IsNullOrWhiteSpace(value) ? currVal : value);
        }
        else
        {
            auditInfo.Value = currentUserId;
        }
    }

    #endregion
}

/// <summary>
/// 表字段 填充标记
/// </summary>
public enum TableFieldFill
{
    /// <summary>
    /// 创建时间
    /// </summary>
    CreateTime,

    /// <summary>
    /// 创建人
    /// </summary>
    CreateId,

    /// <summary>
    /// 更新时间
    /// </summary>
    UpdateTime,

    /// <summary>
    /// 更新人
    /// </summary>
    UpdateId,

    /// <summary>
    /// 删除时间
    /// </summary>
    DeleteTime,

    /// <summary>
    /// 删除人
    /// </summary>
    DeleteId
}